<?php
/**
 * Note: *
 */

namespace App\Caches;

use App\Structs\AdCallbackEventRecord;
use Illuminate\Support\Facades\Redis;

class GameServerCache
{

    private const KEY_PREFIX_SESSION = 'session';
    private const KEY_PREFIX_STOCK_WATER_LINE = 'stockwaterline:scene';
    private const KEY_PREFIX_PRIZE_POOL_BULLET_HB_POOL = 'prizepool:scene';
    private const KEY_PREFIX_SCENE_ONLINE = 'ResetSceneOnline:world';
    private const KEY_PREFIX_NODE_ONLINE = 'node';
    private const KEY_PREFIX_NODE_REFRESH = 'node_refresh';
    private const KEY_PREFIX_AD_CALLBACK = 'ad_callback';

    private const KEY_PLAYER_KV = 'PlayerKV';
    private const KEY_PLAYER_KV_FIELD_ONLINE_TIME_DAY = 'onlineTimeDay';
    private const KEY_PAY_RANK_TASK = 'activityrank:ranksort';
    private const KEY_HB_ACTIVITY_RANK_POOL = 'activityrank:rankpool';

    private const KEY_ORDER_LIST = 'orderList';
    private const KEY_ORDER_COUNT_PACKAGE = 'orderCntPackage';
    private const KEY_ORDER_WARNING = 'orderWarning';
    private const KEY_ORDER_REFUSE_USER = 'orderRefuseUser';
    private const KEY_PAY_TASK_RANK_DEFAULT = 'payrankdefault'; // 奶酪瓜分榜的保底奖励
    private const KEY_MORA_RANK_DEFAULT = 'morarankdefault'; // 猜拳活动的保底奖励

    private const GAME_DB_0 = 0;
    private const GAME_DB_1 = 1;
    private const GAME_DB_2 = 2;
    private const GAME_DB_3 = 3;
    private const GAME_DB_4 = 4;
    private const GAME_DB_5 = 5;

    private static function cache()
    {
        return Redis::connection('game');
    }

    /**
     * 设置SESSION
     * 默认5分钟超时
     * @param string $session
     * @param null $data
     */
    public static function setSession(string $session, $data = null)
    {
        self::cache()->command('SELECT', [self::GAME_DB_0]);
        self::cache()->set(sprintf("%s:%s", self::KEY_PREFIX_SESSION, $session), $data, 'ex', 300);
    }

    /**
     * 获取session对应数据
     * @param string $session
     * @return mixed
     */
    public static function getSession(string $session)
    {
        self::cache()->command('SELECT', [self::GAME_DB_0]);
        return self::cache()->get(sprintf("%s:%s", self::KEY_PREFIX_SESSION, $session));
    }

    /**
     * 获取实时的库存水线值
     * @param int $sceneId
     * @return mixed
     */
    public static function getStockWaterLine(int $sceneId)
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        return self::cache()->hgetall(sprintf("%s:%s", self::KEY_PREFIX_STOCK_WATER_LINE, $sceneId));
    }

    /**
     * 获取实时的J场奶酪池和棒棒糖池
     * @param int $sceneId
     * @return mixed
     */
    public static function getPrizePoolBulletHbPool(int $sceneId)
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        return self::cache()->hgetall(sprintf("%s:%s", self::KEY_PREFIX_PRIZE_POOL_BULLET_HB_POOL, $sceneId));
    }

    /**
     * 场次在线人数
     * @param int $sceneId
     * @return mixed
     */
    public static function getSceneOnline(int $sceneId)
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        $keys = self::cache()->keys(sprintf("%s:*", self::KEY_PREFIX_SCENE_ONLINE));
        $sum = 0;
        foreach ($keys as $key) {
            $scenes = self::cache()->hmget($key, [$sceneId]);
            $sum += $scenes[0] ?? 0;
        }
        return $sum;
    }

    /**
     * 获取节点下所有场次在线人数
     * @param int $nodeId
     * @return int
     */
    public static function getSceneOnlineSum(int $nodeId): int
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        $key = sprintf("%s:%d", self::KEY_PREFIX_SCENE_ONLINE, $nodeId);
        $data = self::cache()->hgetall($key);
        if (!$data) return 0;
        return array_sum(array_values($data));
    }

    /**
     * 删除节点场次在线人数
     * @param int $nodeId
     * @return true
     */
    public static function resetSceneOnline(int $nodeId)
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        $key = sprintf("%s:%d", self::KEY_PREFIX_SCENE_ONLINE, $nodeId);
        $data = self::cache()->hgetall($key);
        foreach ($data as $sceneId => $count) {
            self::cache()->hset($key, $sceneId, 0);
        }
        return true;
    }

    /**
     * 获取所有场次在线人数
     * @return array
     */
    public static function getSceneOnlineAll() :array
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);

        $lists = [];
        $keys = self::cache()->keys(sprintf("%s:*", self::KEY_PREFIX_SCENE_ONLINE));
        foreach ($keys as $key) {
            $scenes = self::cache()->hgetall($key);
            foreach ($scenes as $sceneId => $count) {
                $lists[$sceneId] = ($lists[$sceneId]??0) + $count;
            }
        }
        return $lists;
    }

    /**
     * 玩家KV值
     * @param int $playerId
     * @param string $field
     * @return mixed
     */
    public static function getPlayerKV(int $playerId, string $field)
    {
        self::cache()->command('SELECT', [self::GAME_DB_2]);
        return self::cache()->get(sprintf("%s:%d:%s", self::KEY_PLAYER_KV, $playerId, $field));
    }

    /**
     * 用户当日在线时长
     * @param int $playerId
     * @return int
     */
    public static function getOnlineTimeDay(int $playerId): int
    {
        return self::getPlayerKV($playerId, self::KEY_PLAYER_KV_FIELD_ONLINE_TIME_DAY) ?: 0;
    }

    /**
     * 获取节点在线人数
     * @param string $type
     * @param int $nodeId
     * @return int
     */
    public static function getNodeOnline(string $type, int $nodeId): int
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        return self::cache()->get(sprintf("%s:%s:%s", self::KEY_PREFIX_NODE_ONLINE, $type, $nodeId)) ?: 0;
    }

    /**
     * 重置节点在线人数
     * @param string $type
     * @param int $nodeId
     * @return mixed
     */
    public static function resetNodeOnline(string $type, int $nodeId)
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        return self::cache()->set(sprintf("%s:%s:%s", self::KEY_PREFIX_NODE_ONLINE, $type, $nodeId), 0);
    }

    /**
     * 获取节点刷新超时的场次ID
     * @return array
     */
    public static function getNodeRefreshTimeoutNodeIds(): array
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        $lists = [];
        $keys = self::cache()->keys(sprintf("%s:world:*", self::KEY_PREFIX_NODE_REFRESH));
        foreach ($keys as $key) {
            list(,, $nodeId) = explode(':', $key);
            if (!is_numeric($nodeId)) continue;
            $time = self::cache()->get($key);
            if ((time() - $time) > 20) {
                $lists[] = $nodeId;
            }
        }
        return $lists;
    }

    /**
     * 获取充值瓜分榜
     * @param int $id
     * @param int $issue
     * @return array
     */
    public static function getPayRankTask(int $id, int $issue): array
    {
        self::cache()->command('SELECT', [self::GAME_DB_3]);
        $lists = self::cache()->zrevrange(sprintf("%s:%d:%d", self::KEY_PAY_RANK_TASK, $id, $issue), 0, -1, ['WITHSCORES' => true]);
        return $lists ?: [];
    }

    /**
     * 奶酪瓜分榜的保底奖励
     * @param int $taskId
     * @param int $issue
     * @return int
     */
    public static function getPayTaskRankDefault(int $activityId, int $issue): int
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        return self::cache()->get(sprintf("%s:%d:%d", self::KEY_PAY_TASK_RANK_DEFAULT, $activityId, $issue)) ?: 0;
    }

    /**
     * 猜拳活动的保底奖励
     * @param int $activityId
     * @param int $issue
     * @return int
     */
    public static function getMoraRankDefault(int $activityId, int $issue): int
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        return self::cache()->get(sprintf("%s:%d:%d", self::KEY_MORA_RANK_DEFAULT, $activityId, $issue)) ?: 0;
    }

    /**
     * 棒棒糖场瓜分榜的总奖励
     * @param int $taskId
     * @param int $issue
     * @return int
     */
    public static function getHbActivityRankPool(int $taskId, int $issue): int
    {
        self::cache()->command('SELECT', [self::GAME_DB_1]);
        return self::cache()->get(sprintf("%s:%d:%d", self::KEY_HB_ACTIVITY_RANK_POOL, $taskId, $issue)) ?: 0;
    }

    /**
     * 棒棒糖场瓜分榜的总奖励 多期
     * @param int $taskId
     * @param array $issues
     * @return array
     */
    public static function getHbActivityRankPools(int $taskId, array $issues): array
    {
        $awards = [];
        foreach ($issues as $issue) {
            $awards[$issue] = self::getHbActivityRankPool($taskId, $issue);
        }
        return $awards;
    }

    /**
     * 增加套餐支付次数
     * @param int $playerId
     * @param int $packageId
     * @param int $countLimit
     * @return bool
     */
    public static function addOrderCntByPackage(int $playerId, int $packageId, int $countLimit = 5): bool
    {
        self::cache()->command('SELECT', [self::GAME_DB_5]);

        $key = sprintf("%s:%d", self::KEY_ORDER_COUNT_PACKAGE, $playerId);

        $hasCreate = self::cache()->exists($key);

        $cnt = self::cache()->hincrby($key, $packageId, 1);
        if (!$hasCreate) self::cache()->expire($key, 86400);

        if ($cnt > $countLimit) return false;

        return true;
    }

    /**
     * 删除套餐支付次数
     * @param int $playerId
     * @return int
     */
    public static function delOrderCntByPackage(int $playerId): int
    {
        self::cache()->command('SELECT', [self::GAME_DB_5]);

        $key = sprintf("%s:%d", self::KEY_ORDER_COUNT_PACKAGE, $playerId);
        return self::cache()->del($key);
    }

    /**
     * 记录订单记录
     * {$minuteLimit}分钟内未支付超过{$countLimit}笔, 返回false
     * @param int $playerId
     * @param int $createdTime
     * @param int $countLimit
     * @param int $minuteLimit
     * @return bool
     */
    public static function addOrderList(int $playerId, int $createdTime, int $countLimit = 5, int $minuteLimit = 2): bool
    {
        self::cache()->command('SELECT', [self::GAME_DB_5]);

        $key = sprintf("%s:%d", self::KEY_ORDER_LIST, $playerId);

        // 无数据时设置24小时过期时间
        $len = self::cache()->lpush($key, $createdTime);
        if ($len === 1) self::cache()->expire($key, 86400);

        // 无需判断
        if ($len <= $countLimit) return true;

        // 仅保留$countLimit条
        self::cache()->ltrim($key, 0, $countLimit - 1);

        // 取最后一条与最新一条比较时间
        $firstAt = self::cache()->lindex($key, -1);
        if (($createdTime - $firstAt) <= $minuteLimit*60) {
            return false;
        }
        return true;
    }

    /**
     * 删除订单记录
     * @param int $playerId
     * @return mixed
     */
    public static function delOrderList(int $playerId)
    {
        self::cache()->command('SELECT', [self::GAME_DB_5]);

        $key = sprintf("%s:%d", self::KEY_ORDER_LIST, $playerId);

        return self::cache()->del($key);
    }

    /**
     * 添加警告订单, 超过{$countLimit}笔未支付
     * @param int $playerId
     * @param int $countLimit
     * @return bool
     */
    public static function addOrderWarning(int $playerId, int $countLimit = 3): bool
    {
        self::cache()->command('SELECT', [self::GAME_DB_5]);

        $key = sprintf("%s:%d", self::KEY_ORDER_WARNING, $playerId);

        // 无数据时设置7天过期时间
        $cnt = self::cache()->incr($key, 1);
        if ($cnt === 1) self::cache()->expire($key, 604800);

        if ($cnt > $countLimit) return false;

        return true;
    }

    /**
     * 删除警告订单
     * @param int $playerId
     * @return int
     */
    public static function delOrderWarning(int $playerId): int
    {
        self::cache()->command('SELECT', [self::GAME_DB_5]);

        $key = sprintf("%s:%d", self::KEY_ORDER_WARNING, $playerId);

        return self::cache()->del($key);
    }

    /**
     * 添加订单拒绝用户
     * @param int $playerId
     * @return bool
     */
    public static function addOrderRefuseUser(int $playerId): bool
    {
        self::cache()->command('SELECT', [self::GAME_DB_4]);

        $key = sprintf("%s:%d", self::KEY_ORDER_REFUSE_USER, $playerId);

        return self::cache()->set($key, 1, 'EX', 3600);
    }

    /**
     * 删除被拒绝用户
     * @param int $playerId
     * @return bool
     */
    public static function delOrderRefuseUser(int $playerId): bool
    {
        self::cache()->command('SELECT', [self::GAME_DB_4]);

        $key = sprintf("%s:%d", self::KEY_ORDER_REFUSE_USER, $playerId);

        return self::cache()->del($key);
    }

    /**
     * 检查是否是被拒绝用户
     * @param int $playerId
     * @return bool
     */
    public static function checkOrderRefuseUser(int $playerId): bool
    {
        self::cache()->command('SELECT', [self::GAME_DB_4]);

        $key = sprintf("%s:%d", self::KEY_ORDER_REFUSE_USER, $playerId);

        return self::cache()->exists($key);
    }

    /**
     * 获取被拒绝用户列表和过期时间
     * @return array
     */
    public static function getOrderRefuseUsers(): array
    {
        self::cache()->command('SELECT', [self::GAME_DB_4]);

        $key = sprintf("%s:*", self::KEY_ORDER_REFUSE_USER);

        $keys = self::cache()->keys($key);
        $lists = [];
        foreach ($keys as $k => $key) {
            // $lists[$k]['playerId'] = str_replace(self::KEY_ORDER_REFUSE_USER.':', '', $key);
            // $lists[$k]['ttl'] = self::cache()->ttl($key);
            $playerId = str_replace(self::KEY_ORDER_REFUSE_USER.':', '', $key);;
            $lists[$playerId] = self::cache()->ttl($key);
        }
        return $lists;
    }
}
